package com.example.literj.kt.internal.disposables

import com.example.literj.kt.disposables.Disposable
import com.example.literj.kt.plugins.RxJavaPlugins
import java.util.*
import java.util.concurrent.atomic.AtomicReference

enum class DisposableHelper : Disposable {
    DISPOSED {
        override fun dispose() {}

        override fun isDisposed() = true
    };

    companion object {
        @JvmStatic
        fun isDisposed(disposable: Disposable?): Boolean {
            return disposable == DISPOSED
        }

        @JvmStatic
        fun dispose(field: AtomicReference<Disposable>?): Boolean {
            var cur = field?.get()
            val d = DISPOSED
            if (cur != d) {
                cur = field?.getAndSet(d)
                if (cur != d) {
                    cur?.dispose()
                    return true
                }
            }
            return false
        }

        @JvmStatic
        fun set(field: AtomicReference<Disposable>, d: Disposable?): Boolean {
            while (true) {
                val current = field.get()
                if (current == DISPOSED) {
                    d?.dispose()
                    return false
                }
                if (field.compareAndSet(current, d)) {
                    current?.dispose()
                    return true
                }
            }
        }

        @JvmStatic
        fun setOnce(field: AtomicReference<Disposable>, d: Disposable?): Boolean {
            Objects.requireNonNull(d, "d is null")
            if (!field.compareAndSet(null, d)) {
                d?.dispose()
                if (field.get() != DISPOSED) {
                    reportDisposableSet()
                }
                return false
            }
            return true
        }

        @JvmStatic
        fun replace(field: AtomicReference<Disposable>, d: Disposable?): Boolean {
            while (true) {
                val current = field.get()
                if (current == DISPOSED) {
                    d?.dispose()
                    return false
                }
                if (field.compareAndSet(current, d)) {
                    return true
                }
            }
        }

        fun reportDisposableSet() {
            RxJavaPlugins.onError(IllegalStateException("Disposable already set!"))
        }
    }
}